from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import QTimer, QDateTime, QCoreApplication
from PyQt5.QtGui import QImage, QPixmap, QCloseEvent
from PyQt5.QtWidgets import QMessageBox
from UI import Ui_MainWindow
import sys
import cv2
import serial
import time
PS_Getimage = [0XEF, 0X01, 0XFF, 0XFF, 0XFF, 0XFF, 0X01, 0X00, 0X03, 0X01, 0X00, 0X05]  # 录入图像
PS_GenChar1 = [0xEF, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x04, 0x02, 0x01, 0x00, 0x08]  # 在特征区1生成特征
PS_GenChar2 = [0xEF, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x04, 0x02, 0x02, 0x00, 0x09]  # 在特征区2生成特征
PS_Match = [0xEF, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x03, 0x03, 0x00, 0x07]  # 对比匹配与否
PS_Search_stored1 = [0xEF, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x08, 0x04, 0x01, 0x00, 0x01, 0x00, 0x20,
                             0x00,
                             0x2F]  # 以特征区1的指纹特征进行全局搜索
PS_Search_stored2 = [0xEF, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x08, 0x04, 0x02, 0x00, 0x01, 0x00, 0x20,
                             0x00,
                             0x30]  # 以特征区2的指纹特征进行全局搜索
PS_RegModel = [0xEF, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x03, 0x05, 0x00, 0x09]  # 合并1、2区特征并存于1、2区
PS_StoreChar_1tox = [0xEF, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x06, 0x06, 0x01, 0x00, 0x03, 0x00,
                             0x11]  # 在指纹库指定ID处添加指纹
PS_Empty = [0xEF, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x03, 0x0d, 0x00, 0x11]  # 清空指纹库
PS_DeletChar = [0xEF, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x07, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00,
                        0x16]  # 清空指纹库
global rec_data
rec_data = [3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3]


class fun(QtWidgets.QMainWindow, Ui_MainWindow):
    def __init__(self):
        super(fun, self).__init__()
        self.setupUi(self)

        self.pushButton.clicked.connect(self.timer_play)
        self.pushButton_2.clicked.connect(self.per_recognize)
        self.pushButton_3.clicked.connect(self.luru)
        self.pushButton_4.clicked.connect(self.detect_tem)

        inference_pb = "frozen_inference_graph1.pb"  # pb
        graph_txt = "graph1.pbtxt"
        self.net = self.load_md(graph_txt, inference_pb)

        self.timer1 = QTimer(self)
        self.timer1.timeout.connect(self.detect_mask)  #
        # self.timer1.timeout.connect(self.detect_tem)
        self.capture = None

        self.ser = serial.Serial("COM3", 57600, timeout=0.5)
        self.ser_tem = serial.Serial("COM4", 115200, timeout=0.5)

        self.lineEdit_5.setText("30")
        self.lineEdit_6.setText("46")


    def timer_play(self):
        if self.timer1.isActive():
            self.timer1.stop()

        if self.capture == None:
            self.capture = cv2.VideoCapture(0)
            self.timer1.start(30)
        else:
            self.capture.release()
            self.capture = None
            self.label.clear()

    def per_recognize(self):
        self.label_4.setText("请进行身份验证")
        self.CHECK_FINGERPRINT(self.ser)

    def luru(self):
        self.label_4.setText("请录入指纹!")
        self.ADD_FINGERPRINT(self.ser)

    def detect_tem(self):
        send_str = '3'
        self.send_tem_cmd(send_str)

        tem = float(self.lineEdit.text())
        tem_H = float(self.lineEdit_6.text())
        tem_L = float(self.lineEdit_5.text())

        if tem > tem_H or tem < tem_L:
            self.lineEdit_3.setText("体温异常!请及时就医!")
            pixmap = QPixmap("tem_n.png")
            self.label_6.setPixmap(pixmap)
            self.label_6.setScaledContents(True)  # 适应label的大小
        elif tem < tem_H and tem > tem_L:
            self.lineEdit_3.setText("当前体温正常!")
            pixmap = QPixmap("tem_y.png")
            self.label_6.setPixmap(pixmap)
            self.label_6.setScaledContents(True)  # 适应label的大小
        if tem < 28.0 or tem > 48.0:
            self.tem_flag = 1
            self.lineEdit_3.setText("超出测量范围!")
            pixmap = QPixmap("tem.png")
            self.label_6.setPixmap(pixmap)
            self.label_6.setScaledContents(True)  # 适应label的大小

    def detect_mask(self):
        ret, image = self.capture.read()

        if ret == 0:
            print(" pic is none ")
        self.model_return(self.net, image)

        # (H, W) = image.shape[:2]
        QIm = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)

        QIm = QImage(QIm.data, image.shape[1], image.shape[0], image.shape[1] * image.shape[2],
                     QImage.Format_RGB888)
        self.label.setPixmap(QPixmap.fromImage(QIm))
        self.label.setScaledContents(True)

    def send_cmd(self, str):
        self.ser.write(str.encode())
        print("send successfully!")
        read_str = self.ser.readall()
        if len(read_str) > 0:
            print("recevie successfully!")
            txt = read_str.decode("gbk")
            self.label_4.setText(txt)

    def send_tem_cmd(self, str):

        self.ser_tem.write(str.encode())
        print("send successfully!")
        read_str = self.ser_tem.readall()
        if len(read_str) > 0:
            print("recevie successfully!")
            txt = read_str.decode("gbk")
            self.lineEdit.setText(txt)

    def load_md(self, graph_txt, inference_pb):
        net = cv2.dnn.readNetFromTensorflow(inference_pb,
                                            graph_txt)  # 旧版 需要手动在cv2文件夹里更换cv2.cp37-win_amd64.pyd      10fps
        # net = cv.dnn.readNetFromModelOptimizer(graph_xml, inference_bin)  # openvino 需要手动在cv2文件夹里更换cv2.pyd  60fps
        # net.setPreferableBackend(DNN_BACKEND_INFERENCE_ENGINE)  # openvino加速    # 默认设置 可以不添加
        # net.setPreferableTarget(DNN_TARGET_CPU)  # 。。
        # net.setPreferableTarget(cv2.dnn.DNN_TARGET_MYRIAD)
        print("openvino ok")
        return net

    def model_return(self, net, frame):
        h, w = frame.shape[:2]
        im_tensor = cv2.dnn.blobFromImage(frame, size=(300, 300), swapRB=True, crop=False)
        net.setInput(im_tensor)
        cvOut = net.forward()
        for detect in cvOut[0, 0, :, :]:
            # detect = detect.tolist()  # numpy  ->  list
            score = detect[2]
            left = detect[3] * w
            top = detect[4] * h
            right = detect[5] * w
            bottom = detect[6] * h

            if int(detect[1]) == 1:  # 画框
                if score > 0.9:
                    cv2.putText(frame, str(1), (int(left), int(top)), 1, 3, (0, 255, 255), 1)
                    cv2.rectangle(frame, (int(left), int(top)), (int(right), int(bottom)), (0, 255, 255), 4)
                    self.lineEdit_2.setText("口罩佩戴正常!")
                    pixmap = QPixmap("yes.jpg")
                    self.label_5.setPixmap(pixmap)
                    self.label_5.setScaledContents(True)  # 适应label的大小

            elif int(detect[1]) == 2:
                if score > 0.8:
                    cv2.putText(frame, str(2), (int(left), int(top)), 1, 1.2, (255, 0, 255), 2)
                    cv2.rectangle(frame, (int(left), int(top)), (int(right), int(bottom)), (255, 0, 255), 4)
                    self.lineEdit_2.setText("请正确佩戴口罩!")
                    pixmap = QPixmap("no.jpg")
                    self.label_5.setPixmap(pixmap)
                    self.label_5.setScaledContents(True)  # 适应label的大小
            elif int(detect[1]) == 3:
                if score > 0.4:
                    cv2.putText(frame, str(3), (int(left), int(top)), 1, 1.2, (255, 0, 255), 2)
                    cv2.rectangle(frame, (int(left), int(top)), (int(right), int(bottom)), (255, 0, 255), 4)
                    self.lineEdit_2.setText("请佩戴口罩!")
                    pixmap = QPixmap("no.jpg")
                    self.label_5.setPixmap(pixmap)
                    self.label_5.setScaledContents(True)  # 适应label的大小

    def Send_A_Cmd(self, serInstance, atCmdStr):

        # print("Command: %s" % atCmdStr)
        serInstance.write(atCmdStr)

    def receive_data(self, ser):
        global rec_data
        while not (ser.inWaiting() > 0):
            pass
        rec_data = []
        time.sleep(0.1)
        if ser.inWaiting() > 0:
            for num in range(0, ser.inWaiting()):
                rec_data.insert(num, ser.read(1))
        ##===========调试用===========
        # if rec_data != [3,3,3,3,3,3,3,3,3,3]:
        #     if rec_data != []:
        #         print( rec_data )  # 可以接收中文

    def check_and_set(self, ID):
        check = 0
        PS_StoreChar_1tox[11] = (ID // 256) % 256
        PS_StoreChar_1tox[12] = ID % 256
        check = PS_StoreChar_1tox[6] + (PS_StoreChar_1tox[7] * 256) + PS_StoreChar_1tox[8] + PS_StoreChar_1tox[9] + \
                PS_StoreChar_1tox[10] + (PS_StoreChar_1tox[11] * 256) + PS_StoreChar_1tox[12]
        PS_StoreChar_1tox[13] = (check // 256) % 256
        PS_StoreChar_1tox[14] = check % 256

    def ADD_FINGERPRINT(self, ser):
        global ID
        #ID = eval(input("请输入ID: "))
        ID = int(self.lineEdit_4.text())
        while ID < 1 or ID > 200:
            #ID = eval(input("ID不正确，请重新输入(1-200): "))
            self.label_4.setText("ID不正确，请重新输入(1-200)")
            ID = int(self.lineEdit_4.text())
        print("请第一次输入指纹！")
        self.label_4.setText("请第一次输入指纹！")
        while rec_data[9] != b'\x00':  # 改成do while
            self.Send_A_Cmd(ser, PS_Getimage)
            self.receive_data(ser)
        rec_data[9] = 3
        while rec_data[9] != b'\x00':
            self.Send_A_Cmd(ser, PS_GenChar1)
            self.receive_data(ser)
        rec_data[9] = 3
        print("请第二次输入指纹！")
        self.label_4.setText("请第二次输入指纹！")
        while rec_data[9] != b'\x00':
            self.Send_A_Cmd(ser, PS_Getimage)
            self.receive_data(ser)
        rec_data[9] = 3
        while rec_data[9] != b'\x00':
            self.Send_A_Cmd(ser, PS_GenChar2)
            self.receive_data(ser)
        rec_data[9] = 3
        print("两次指纹匹配结果： ")
        self.Send_A_Cmd(ser, PS_Match)
        self.receive_data(ser)
        if rec_data[9] != b'\x00':
            print("不匹配！录入指纹失败！")
            self.label_4.setText("录入失败")
            return 0
        else:
            print("匹配！")
            self.label_4.setText("录入成功")
        rec_data[9] = 3
        while rec_data[9] != b'\x00':
            self.Send_A_Cmd(ser, PS_RegModel)
            self.receive_data(ser)
        print("合成特征成功！")
        self.label_4.setText("合成特征成功")
        rec_data[9] = 3
        self.check_and_set(ID);
        self.Send_A_Cmd(ser, PS_StoreChar_1tox)
        self.receive_data(ser)
        if rec_data[9] == b'\x00':
            print("录入指纹成功！")
            self.label_4.setText("录入指纹成功")
            rec_data[9] = 3
            return 1
        return 0

    def CHECK_FINGERPRINT(self, ser):
        self.label_4.setText("正在验证!请稍后..")
        rec_data[9] = 3
        while rec_data[9] != b'\x00':
            self.Send_A_Cmd(ser, PS_Getimage)
            self.receive_data(ser)
        rec_data[9] = 3
        while rec_data[9] != b'\x00':
            self.Send_A_Cmd(ser, PS_GenChar1)
            self.receive_data(ser)
        rec_data[9] = 3
        self.Send_A_Cmd(ser, PS_Search_stored1)
        self.receive_data(ser)
        if rec_data[9] == b'\x00':
            print("身份验证成功！ID= %d" % int.from_bytes(rec_data[10] * 256 + rec_data[11], byteorder='big', signed=False))
            self.label_4.setText("验证成功")
            REID = int.from_bytes(rec_data[10] * 256 + rec_data[11], byteorder='big', signed=False)
            self.lineEdit_4.setText(str(REID))
            #return 1
        elif rec_data[9] == b'\x09':
            print("身份验证错误！指纹库中没有匹配的身份！")
            self.label_4.setText("身份验证错误！指纹库中没有匹配的身份！")
            self.lineEdit_4.clear()
            #return 0
        elif rec_data[9] == b'\x01':
            print("数据收包错误！")
            self.label_4.setText("数据收包错误")
            #return 2

    def CLEAR_LIBRARY(self, ser):
        rec_data[9] = 3
        while rec_data[9] != b'\x00':
            self.Send_A_Cmd(ser, PS_Empty)
            self.receive_data(ser)
        print("指纹库已清空!")
        #return 1

    def check_and_set_delete(self, ID, delete_num):
        global det_check
        PS_DeletChar[10] = (ID // 256) % 256
        PS_DeletChar[11] = ID % 256
        PS_DeletChar[12] = (delete_num // 256) % 256
        PS_DeletChar[13] = delete_num % 256
        det_check = PS_DeletChar[6] + (PS_DeletChar[7] * 256) + PS_DeletChar[8] + PS_DeletChar[9] + (
                PS_DeletChar[10] * 256) + \
                    PS_DeletChar[11] + (PS_DeletChar[12] * 256) + PS_DeletChar[13]
        PS_DeletChar[14] = (det_check // 256) % 256
        PS_DeletChar[15] = det_check % 256

    def DELETE_FINGERPRINTS(self, ser):
        ID, delete_num = input(
            "请输入要删除指纹的ID范围（ID、几个）：").split()  # =======================================================
        self.check_and_set_delete(eval(ID), eval(delete_num))
        rec_data[9] = 3
        self.Send_A_Cmd(ser, PS_DeletChar)
        self.receive_data(ser)
        if rec_data[9] == b'\x00':
            print("成功删除 ID= %d 起的 %d 个指纹" % (eval(ID), eval(delete_num)))
        elif rec_data[9] == b'\x01':
            print("数据收包错误!")
        elif rec_data[9] == b'\x10':
            print("删除模板失败！")
        return 1


if __name__ == '__main__':

    app = QtWidgets.QApplication(sys.argv)
    main_ui = fun()
    main_ui.show()
    sys.exit(app.exec_())
